/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#ifndef OBJECT_STORAGE_NODETASKMANAGER_H
#define OBJECT_STORAGE_NODETASKMANAGER_H
#include <string>
#include <vector>
#include <set>
#include <sstream>
#include  <functional>
#include "CommonStruct.h"
namespace OBSPlugin {
    class NodePrefixEntity {
    public:
        NodePrefixEntity() = default;
        explicit NodePrefixEntity(const std::vector<PrefixInfo>& prefixInfo);
        /**
        * Add a object entity to the PrefixInfo
        * @param prefixInfo The prefix entity to add.
        */
        void AddPrefixInfo(const PrefixInfo& prefixInfo);

        /**
        * Add object list to the PrefixInfo
        * @param prefixInfoList The prefix list to add.
        */
        void AddPrefixInfoList(const std::vector<PrefixInfo>& prefixInfoList);

        /**
        * Compute difference between contents of two NodePrefixEntity.
        * @param nodePrefixEntity Second nodePrefixEntity.
        * @return Difference of prefixInfo.
        */
        NodePrefixEntity operator - (NodePrefixEntity const & nodePrefixEntity) const;
        /**
        * Combine contents of two nodePrefixEntity.
        * @param nodePrefixEntity Second nodePrefixEntity.
        * @return Combined nodePrefixEntity.
        */
        NodePrefixEntity operator + (NodePrefixEntity const & nodePrefixEntity) const;

        std::vector<PrefixInfo> GetPrefixInfo();
        /**
        * Count entities in NodePrefixEntity.
        * @return Number of entities.
        */
        size_t EntityCount();

        void Remove(const NodePrefixEntity& nodePrefixEntity);

        void Clear();

        static bool Cmp(const PrefixInfo& a, const PrefixInfo& b)
        {
            return a.buildKey() < b.buildKey();
        }
        struct Compare {
            bool operator () (const PrefixInfo& a, const PrefixInfo& b) const
            {
                return Cmp(a, b);
            }
        };
        friend class PrefixEntityIterator;
    private:
        void ExpandPrefixInfo(const PrefixInfo& prefixInfo);
    private:
        std::set<PrefixInfo, Compare> m_contents;
    };
   
    class PrefixEntityIterator {
    public:
        explicit PrefixEntityIterator(NodePrefixEntity* entity);
        ~PrefixEntityIterator() = default;
        void Next();
        PrefixInfo& Current();
        bool End() const;
        bool Empty() const;
        void operator ++ (int);
    private:
        NodePrefixEntity*  m_nodePrefixEntity;
        std::set<PrefixInfo, NodePrefixEntity::Compare>::iterator m_prefixIt;
    };

    class NodeTaskManager {
    public:
        NodeTaskManager() = default;

        /**
        * 根据本次列举的桶前缀以及上一次副本元数据重新分配节点.
        * @param curBucketPrefixs 当前扫描的桶前缀信息.
        * @param repoEsnList 数据仓的ESN列表.
        * @param lastObjectInfos 上一个副本元数据信息,全量备份首次分配时传空
        * @return 重新分配后节点信息.
        */
        std::vector<BackupObjectInfo> AllocateNodePrefix(const std::vector<PrefixInfo>& curBucketPrefixs,
            const std::vector<std::string>& repoEsnList,
            std::vector<BackupObjectInfo>& lastObjectInfos);
    private:
        std::vector<BackupObjectInfo> FirstAllocateNode(const std::vector<PrefixInfo>& curBucketPrefixs,
            const std::vector<std::string>& repoEsnList);

        // 将toAllocatePrefix的前缀信息平均分配到mergeObjectInfos中
        void ReallocatePrefixNode(NodePrefixEntity& toAllocatePrefix,
            std::vector<BackupObjectInfo>& mergeObjectInfos);
        // 将toRemovePrefix的前缀信息从mergeObjectInfos移除
        void RemovePrefixNode(NodePrefixEntity& toRemovePrefix,
            std::vector<BackupObjectInfo>& mergeObjectInfos);

        NodePrefixEntity MergeNodePrefix(const std::vector<BackupObjectInfo>& objectInfos);
        std::vector<uint32_t> AverageAssign(uint32_t prefixCount, uint32_t nodeCount);
    };
}
#endif
